package com.weaver.qfengx;

import org.junit.Test;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;

/**
 * 日期相关工具类
 *
 * @Author Qfeng
 * @Date 2020-01-09 11:44:45
 */
public class DateUtils {


    private static final long ONE_MINUTE = 60000L;
    private static final long ONE_HOUR = 3600000L;
    private static final long ONE_DAY = 86400000L;
    private static final long ONE_WEEK = 604800000L;

    private static final String ONE_SECOND_AGO = "秒前";
    private static final String ONE_MINUTE_AGO = "分钟前";
    private static final String ONE_HOUR_AGO = "小时前";
    private static final String ONE_DAY_AGO = "天前";
    private static final String ONE_MONTH_AGO = "月前";
    private static final String ONE_YEAR_AGO = "年前";


    @Test
    public void test01() throws ParseException {
        System.out.println(relative(DateUtils.parse("2020-10-10")));
    }

    public static String relative(Date date) {
        return relative(date, ONE_DAY * 3, "yyyy-MM-dd HH:mm:ss");
    }

    public static String relative(Date date, long maxOffset) {
        return relative(date, maxOffset, "yyyy-MM-dd HH:mm:ss");
    }

    public static String relative(Date date, String partten) {
        return relative(date, ONE_DAY * 3, partten);
    }

    /**
     * 计算两个时间的相对时间如 1分钟前、9小时前等
     *
     * @param date      相对时间
     * @param maxOffset 最大间隔数，超过最大间隔将直接返回时间
     * @param partten   超过最大间隔将直接返回时间格式
     * @return
     */
    public static String relative(Date date, long maxOffset, String partten) {
        long delta = new Date().getTime() - date.getTime();
        if (delta > maxOffset) {
            return DateUtils.date(date, partten);
        }
        if (delta < 1L * ONE_MINUTE) {
            long seconds = toSeconds(delta);
            return (seconds <= 0 ? 1 : seconds) + ONE_SECOND_AGO;
        }
        if (delta < 45L * ONE_MINUTE) {
            long minutes = toMinutes(delta);
            return (minutes <= 0 ? 1 : minutes) + ONE_MINUTE_AGO;
        }
        if (delta < 24L * ONE_HOUR) {
            long hours = toHours(delta);
            return (hours <= 0 ? 1 : hours) + ONE_HOUR_AGO;
        }
        if (delta < 48L * ONE_HOUR) {
            return "昨天";
        }
        if (delta < 30L * ONE_DAY) {
            long days = toDays(delta);
            return (days <= 0 ? 1 : days) == 2 ? "前天" : (days <= 0 ? 1 : days) + ONE_DAY_AGO;
        }
        if (delta < 12L * 4L * ONE_WEEK) {
            long months = toYears(delta);
            return (months <= 0 ? 1 : months) + ONE_MONTH_AGO;
        } else {
            long years = delta / 365L;
            return (years <= 0 ? 1 : years) + ONE_YEAR_AGO;
        }
    }


    private static long toSeconds(long date) {
        return date / 1000L;
    }

    private static long toMinutes(long date) {
        return toSeconds(date) / 60L;
    }

    private static long toHours(long date) {
        return toMinutes(date) / 60L;
    }

    private static long toDays(long date) {
        return toHours(date) / 24L;
    }

    private static long toMonths(long date) {
        return toDays(date) / 30L;
    }

    private static long toYears(long date) {
        return toMonths(date) / 365L;
    }

    public static String min(String date1, String date2) {
        try {
            if (StringUtils.isEmpty(date1)) return date2;
            if (StringUtils.isEmpty(date2)) return date1;
            long time1 = parse(date1).getTime();
            long time2 = parse(date2).getTime();
            return time1 < time2 ? date1 : date2;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static String max(String date1, String date2) {
        try {
            if (StringUtils.isEmpty(date1)) return date2;
            if (StringUtils.isEmpty(date2)) return date1;
            long time1 = parse(date1).getTime();
            long time2 = parse(date2).getTime();
            return time1 > time2 ? date1 : date2;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static boolean checkBetween(String datetime, String date1, String date2) {
        try {
            long time1 = parse(date1).getTime();
            long time2 = parse(date2).getTime();
            long check = parse(datetime, "yyyy-MM-dd HH:mm:ss").getTime();
            return check >= time1 && check <= time2;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static Date now() {
        return new Date();
    }

    public static Date parse(String date) throws ParseException {
        return parse(date, "yyyy-MM-dd");
    }

    public static Date parse(String date, String pattern) throws ParseException {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.parse(date);
    }

    /**
     * 根据给定日期 和 格式串 返回指定格式日期时间
     *
     * @param date    日期时间
     * @param partten 格式串
     * @return 指定格式日期时间
     */
    public static String date(Date date, String partten) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(partten);
        return dateFormat.format(date);
    }

    public static Date getDate(Date date, String pattern) throws ParseException {
        return new SimpleDateFormat(pattern).parse(date(date, pattern));
    }

    public static Date getDate(Date date) throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd").parse(date(date, "yyyy-MM-dd"));
    }

    public static Date getDate() throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd").parse(date(new Date(), "yyyy-MM-dd"));
    }

    public static Date getDate(String pattern) throws ParseException {
        return new SimpleDateFormat(pattern).parse(date(new Date(), pattern));
    }

    /**
     * 根据格式串返回当前日期时间指定格式
     *
     * @param pattern 格式串
     * @return 当前日期时间指定格式
     */
    public static String date(String pattern) {
        return date(new Date(), pattern);
    }

    /**
     * 返回yyyy-MM-dd 格式指定日期时间
     *
     * @param date 指定日期时间
     * @return yyyy-MM-dd 格式指定日期时间
     */
    public static String date(Date date) {
        return date(date, "yyyy-MM-dd");
    }

    /**
     * 返回yyyy-MM-dd 格式当前日期时间
     *
     * @return yyyy-MM-dd 格式当前日期时间
     */
    public static String date() {
        return date("yyyy-MM-dd");
    }


    /**
     * 返回指定间隔天数的日期
     *
     * @param date   指定日期
     * @param offset 指定偏移量(天)
     * @return 指定间隔天数的日期 (yyyy-MM-dd)
     */
    public static String date(Date date, int offset) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, offset);
        return date(calendar.getTime());
    }

    public static String offset(int offset) {
        return date(new Date(), offset);
    }

    /**
     * 返回指定间隔天数的当前日期
     *
     * @param offset 指定偏移量(天)
     * @return 指定间隔天数的房前日期 (yyyy-MM-dd)
     */
    public static String date(int offset) {
        return date(new Date(), offset);
    }

    /**
     * 返回yyyy-MM-dd HH:mm:ss格式日期时间
     *
     * @return yyyy-MM-dd HH:mm:ss格式日期时间
     */
    public static String datetime() {
        return datetime(new Date());
    }

    public static String datetime(Date date) {
        return date(date, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 返回HH:mm:ss格式时间
     *
     * @return HH:mm:ss格式时间
     */
    public static String time() {
        return date("HH:mm:ss");
    }

    public static String time(Date date) {
        return date(date, "HH:mm:ss");
    }

    /**
     * 返回指定日期偏移天数的起始时间
     *
     * @param date   日期
     * @param offset 偏移量
     * @return 指定日期偏移天数的起始时间
     */
    public static Date dayStart(Date date, int offset) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, offset);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /**
     * 当前日期的起始时间
     *
     * @return 当前日期的起始时间
     */
    public static Date dayStart() {
        return dayStart(new Date(), 0);
    }

    /**
     * 当前日期的偏移量起始时间
     *
     * @param offset 偏移量
     * @return 当前日期的偏移量起始时间
     */
    public static Date dayStart(int offset) {
        return dayStart(new Date(), offset);
    }

    /**
     * 指定日期指定偏移天数结束时间
     *
     * @param date   指定日期
     * @param offset 指定偏移天数
     * @return 指定日期指定偏移天数结束时间
     */
    public static Date dayEnd(Date date, int offset) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, offset);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return calendar.getTime();
    }

    /**
     * 当前日期结束时间
     *
     * @return 当前日期结束时间
     */
    public static Date dayEnd() {
        return dayEnd(new Date(), 0);
    }

    /**
     * 当前日期指定偏移天数结束时间
     *
     * @param offset 偏移天数
     * @return 当前日期指定偏移天数结束时间
     */
    public static Date dayEnd(int offset) {
        return dayEnd(new Date(), offset);
    }

    /**
     * 时间戳
     *
     * @return 时间戳
     */
    public static String timestamp() {
        return String.valueOf(System.currentTimeMillis());
    }

    public static boolean equals(Date date1, Date date2) {
        if (date1 == null && date2 != null)
            return false;
        if (date1 == date2)
            return true;
        if (date1.equals(date2))
            return true;
        return date1.getTime() == date2.getTime();
    }

    public static String toUTC(Date date, String pattern, String timeZone) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeZone(TimeZone.getTimeZone(timeZone));
        calendar.get(Calendar.ZONE_OFFSET);
        return date(new Date(date.getTime() - calendar.get(Calendar.ZONE_OFFSET)), pattern);
    }

    public static String toUTC(Date date, String pattern) {
        return toUTC(date, pattern, TimeZone.getDefault().getID());
    }

    public static String toUTC(String pattern) {
        Calendar calendar = Calendar.getInstance();
        calendar.get(Calendar.ZONE_OFFSET);
        return date(new Date(new Date().getTime() - calendar.get(Calendar.ZONE_OFFSET)), pattern);
    }

    public static String toUTC() {
        Calendar calendar = Calendar.getInstance();
        calendar.get(Calendar.ZONE_OFFSET);
        return date(new Date(new Date().getTime() - calendar.get(Calendar.ZONE_OFFSET)), "yyyy-MM-dd HH:mm:ss");
    }

    /**
     *  获取某月的最后一天
     */
    public static String getLastDayOfMonth(int year, int month, String pattern) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1); // 从0开始
        int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, lastDay);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(calendar.getTime());
    }

    public static String getLastDayOfMonth(int year, int month) {
        return getLastDayOfMonth(year, month, "yyyy-MM-dd");
    }

    public static String getDate(int year, int month, int day, String pattern) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1); // 从0开始
        calendar.set(Calendar.DAY_OF_MONTH, day);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(calendar.getTime());
    }

    public static String getDate(int year, int month, int day) {
        return getDate(year, month, day, "yyyy-MM-dd");
    }

    /**
     *  获取某月的最后一天
     */
    public static String getLastDayOfMonth(Date date, String pattern) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, lastDay);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
        return simpleDateFormat.format(calendar.getTime());
    }

    public static String getLastDayOfMonth(Date date) {
        return getLastDayOfMonth(date, "yyyy-MM-dd");
    }


    public static Date parseString(String dateStr, String pattern) throws ParseException {
        DateFormat df = new SimpleDateFormat(pattern);
        Date date = df.parse(dateStr);
        return date;
    }

    public static Date parseString(String dateStr) throws ParseException {
        return parseString(dateStr, "yyyy-MM-dd");
    }

    public static Long timestamp(String dateStr, String pattern) throws ParseException {
        Date date = parseString(dateStr, pattern);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return cal.getTimeInMillis();
    }

    /**
     *
     * @param dateStr yyyy-MM-dd HH:mm:ss格式
     * @return
     * @throws ParseException
     */
    public static Long timestamp(String dateStr) throws ParseException {
        return timestamp(dateStr, "yyyy-MM-dd HH:mm:ss");
    }

    public static void main(String[] args) throws ParseException {
//        System.out.println(TimeZone.getDefault().getDisplayName());
//        System.out.println(TimeZone.getTimeZone("Europe/Rome").getDisplayName());
//        System.out.println(toUTC(new Date(), "yyyy-MM-dd HH:mm:ss", "Europe/Rome"));
//        System.out.println(DateUtils.offset(0));
        System.out.println(DateUtils.getLastDayOfMonth(2021, 5));
        System.out.println(DateUtils.getLastDayOfMonth(DateUtils.parse("2021-02-01")));
    }

}
